package cn.bonoon.kernel.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.UUID;

public final class MD5Util extends CryptoUtil {
	protected static MessageDigest messagedigest = null;
	private static volatile SecureRandom numberGenerator = null;
	
	static {
		try {
			messagedigest = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException nsaex) {
//			System.err.println(MD5Util.class.getName()
//					+ "初始化失败，MessageDigest不支持MD5Util。");
			nsaex.printStackTrace();
		}
	}

	/** 适用于上G大的文件 */
	public static byte[] getFileMD5(File file) throws IOException {
		FileInputStream in = new FileInputStream(file);
		FileChannel ch = in.getChannel();
		MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
		messagedigest.update(byteBuffer);
		return messagedigest.digest();
	}

	public static byte[] randomMD5() {
		SecureRandom ng = numberGenerator;
		if (ng == null) {
			numberGenerator = ng = new SecureRandom();
		}

		byte[] randomBytes = new byte[16];
		ng.nextBytes(randomBytes);
		return randomBytes;
	}

	/** 随机MD5码，加密的16进制使用小写字母 */
	public static String randomMD5String() {
		return toHex(randomMD5());
	}
	
	/** 随机MD5码，转为BASE64的输出编码 */
	public static String randomBase64(){
		return toBase64(randomMD5());
	}

	public static UUID getFileUUID(File file) throws IOException {
		byte[] md5Bytes = getFileMD5(file);
		md5Bytes[6] &= 0x0f; /* clear version */
		md5Bytes[6] |= 0x30; /* set to version 3 */
		md5Bytes[8] &= 0x3f; /* clear variant */
		md5Bytes[8] |= 0x80; /* set to IETF variant */
		long msb = 0, lsb = 0;
		assert md5Bytes.length == 16;
		for (int i = 0; i < 8; i++)
			msb = (msb << 8) | (md5Bytes[i] & 0xff);
		for (int i = 8; i < 16; i++)
			lsb = (lsb << 8) | (md5Bytes[i] & 0xff);
		return new UUID(msb, lsb);
	}

	/** 加密的16进制使用小写字母 */
	public static String getFileMD5String(File file) throws IOException {
		return toHex(getFileMD5(file));
	}

	/** 加密的16进制使用小写字母 */
	public static String getMD5(String s) {
		return toHex(getMD5(s.getBytes()));
	}

	public static byte[] getMD5(byte[] bytes) {
		messagedigest.update(bytes);
		return messagedigest.digest();
	}

	public static void main(String[] args){
		System.out.println(randomBase64());
	}
}
